package com.hhkj.admin.order.common.component.checker;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.hhkj.admin.course.domain.Course;
import com.hhkj.admin.course.domain.CourseBankType;
import com.hhkj.admin.order.common.cont.ExceptionCodeEnum;
import com.hhkj.admin.order.common.exception.StudentEnrolledException;
import com.hhkj.admin.order.model.dopo.OrderItemDo;
import com.hhkj.admin.order.model.dopo.OrderItemPo;
import com.hhkj.admin.order.service.base.OrderItemService;
import com.hhkj.admin.course.domain.CoursePriceConf;
import com.hhkj.admin.course.service.base.CourseBankTypeService;
import com.hhkj.admin.course.service.base.CoursePriceConfService;
import com.hhkj.admin.course.service.base.CourseService;
import com.hhkj.admin.order.common.component.validator.*;
import com.hhkj.admin.order.common.cont.OrderConst;
import com.hhkj.admin.order.common.exception.InvalidOrderItemException;
import com.hhkj.admin.order.domain.OrderItem;
import com.hhkj.admin.student.common.cont.StudentConst;
import com.hhkj.admin.student.domain.StudentCourse;
import com.hhkj.admin.student.service.base.StudentCourseService;
import com.ruoyi.common.base.model.extend.ValidError;
import com.ruoyi.common.cont.SysConst;
import com.ruoyi.common.exception.GlobalErrorListException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * OrderItemChecker
 *
 * @author HHKJ-SERVER-ZJ
 * @since 2023/11/2 17:36
 */
@Component
public class OrderItemChecker {

    private static final Logger logger = LoggerFactory.getLogger(OrderItemChecker.class);

    @Autowired
    private CourseService courseService;
    @Autowired
    private CourseBankTypeService courseBankTypeService;
    @Autowired
    private CoursePriceConfService coursePriceConfService;
    @Autowired
    private StudentCourseService studentCourseService;
    @Autowired
    private OrderItemService orderItemService;

    /**
     * 校验子订单信息，此校验用于支付订单前的校验
     * 如果全部正确 : 返回成功标识为true，且没有失错误信息
     * 如果出现错误 : 错误信息会在返回值中说明原因
     * @param orderItemList 子订单列表
     * @return 结果，如果错误则会说明原因
     */
    public List<ValidError<OrderItem>> checkBeforePayOrder(List<? extends OrderItem> orderItemList) {
        List<BaseOrderItemValidateStrategy> validateStrategyList =
                buildValidateStrategyList(orderItemList, null, OrderConst.ValidateType.BEFORE_PAY);
        return doCheck(orderItemList, validateStrategyList);
    }

    public List<? extends OrderItem> checkBeforePayOrder(Long orderId) {
        //获取订单item列表
        OrderItemDo orderItemDo = new OrderItemDo();
        orderItemDo.setOrderId(orderId);
        List<OrderItemPo> orderItemPoList = orderItemService.listPoByDo(orderItemDo);

        //对订单item进行校验，查看是否通过
        List<ValidError<OrderItem>> validErrorList = checkBeforePayOrder(orderItemPoList);
        if (CollectionUtil.isEmpty(validErrorList) == false) {
            String message = assembleMessage(validErrorList);
            throw new GlobalErrorListException(validErrorList, message);
        }
        return orderItemPoList;
    }

    /**
     * 创建订单校验
     * @param orderItemList 订单子项咧列表
     */
    public List<ValidError<OrderItem>> checkBeforeCreateOrder(List<? extends OrderItem> orderItemList, OrderConst.SourceTypeCode sourceTypeCode) {
        List<BaseOrderItemValidateStrategy> validateStrategyList =
                buildValidateStrategyList(orderItemList, sourceTypeCode, OrderConst.ValidateType.BEFORE_CREATE);
        return doCheck(orderItemList, validateStrategyList);
    }

    private List<ValidError<OrderItem>> doCheck(List<? extends OrderItem> orderItemList, List<BaseOrderItemValidateStrategy> validateStrategyList) {
        List<ValidError<OrderItem>> validErrorList = new ArrayList<>();
        int i = 0;
        OrderItem orderItem = null;
        //进行数据校验
        for (; i < orderItemList.size(); i++) {
            try {
                orderItem = orderItemList.get(i);
                //校验基础信息
                isValidBasicInfo(orderItem);
                //校验其他信息
                OrderItem finalOrderItem = orderItem;
                validateStrategyList.forEach(validateStrategy -> validateStrategy.validate(finalOrderItem));
            } catch (StudentEnrolledException e) {
                validErrorList.add(new ValidError<>(i + 1, orderItem, e.getMessage(), ExceptionCodeEnum.ENROLL.getCode()));
            } catch (InvalidOrderItemException e) {
                validErrorList.add(new ValidError<>(i + 1, orderItem, e.getMessage()));
            }
        }
        return validErrorList;
    }

    private boolean isValidBasicInfo(OrderItem orderItem) {
        //校验名称
        OrderItemValidator.isValidName(orderItem);
        //校验身份证号
        OrderItemValidator.isValidIdCard(orderItem);
        //校验手机号
        OrderItemValidator.isValidPhone(orderItem);
        return true;
    }

    /**
     * 构建校验逻辑
     * @param orderItemList 子订单列表
     * @param sourceTypeCode 订单来源，（validateType为支付前时，这个参数不重要，可以为null）
     * @param validateType 校验类型 （支付前 或者 创建前）
     * @return
     */
    private List<BaseOrderItemValidateStrategy> buildValidateStrategyList(List<? extends OrderItem> orderItemList,
                                                                          OrderConst.SourceTypeCode sourceTypeCode,
                                                                          OrderConst.ValidateType validateType) {
        List<BaseOrderItemValidateStrategy> validateStrategyList = new ArrayList<>();
        List<String> isCardList = new ArrayList<>();
        List<String> courseNameList = new ArrayList<>();
        List<Long> courseIdList = new ArrayList<>();
        List<Long> coursePriceIdList = new ArrayList<>();
        for (OrderItem item : orderItemList) {
            courseNameList.add(item.getCourseName());
            isCardList.add(item.getIdCard());
            courseIdList.add(item.getCourseId());
            coursePriceIdList.add(item.getCoursePriceId());
        }

        List<Course> allCourseList = null;
        //创建订单前的校验逻辑
        if (OrderConst.ValidateType.BEFORE_CREATE.equals(validateType)) {
            List<Long> parentIdList = null;
            Map<Long, Long> courseIdParentIdMap = null;
            if (OrderConst.SourceTypeCode.SYSTEM.equals(sourceTypeCode)) { //系统导入订单
                //获取 （科目名称-科目信息）map映射表，校验科目名称是否合法，以及该名字的科目是否存在
                allCourseList = courseService.listByNameList(courseNameList, SysConst.Flag.NO.getFlag());
                Map<String, List<Course>> courseNameMap = allCourseList.stream().collect(Collectors.groupingBy(Course::getName));
                validateStrategyList.add(new SysCourseValidatorStrategy(courseNameMap));

                //获取（科目id-科目父类id）map映射表
                parentIdList = allCourseList.stream().map(Course::getParentId).collect(Collectors.toList());
                courseIdParentIdMap = allCourseList.stream().collect(Collectors.toMap(Course::getId, Course::getParentId));

                //获取（科目id-科目价格信息）map映射表，校验价格和天数是否和系统配置的一样
                Map<Long, List<CoursePriceConf>> coursePriceMap = coursePriceConfService.groupByCourseIdList(parentIdList);
                validateStrategyList.add(new SysCoursePriceValidateStrategy(coursePriceMap, courseIdParentIdMap));
            } else if (OrderConst.SourceTypeCode.APP.equals(sourceTypeCode)) { //app创建订单
                //获取（科目id - 科目信息）map映射表
                allCourseList = courseService.listByIdList(courseIdList, SysConst.Flag.NO.getFlag());
                Map<Long, Course> courseMap = allCourseList.stream().collect(Collectors.toMap(Course::getId, course -> course));
                validateStrategyList.add(new AppCourseValidateStrategy(courseMap));

                //获取（科目id-科目父类id）map映射表
                parentIdList = allCourseList.stream().map(Course::getParentId).collect(Collectors.toList());
                courseIdParentIdMap = allCourseList.stream().collect(Collectors.toMap(Course::getId, Course::getParentId));

                //获取（科目价格id - 科目价格信息）map映射表
                Map<Long, CoursePriceConf> coursePriceConfMap = coursePriceConfService.listByIdList(coursePriceIdList)
                        .stream().collect(Collectors.toMap(CoursePriceConf::getId, coursePriceConf -> coursePriceConf));
                validateStrategyList.add(new AppCoursePriceValidateStrategy(coursePriceConfMap, courseIdParentIdMap));
            }
            //获取（科目id-科目默认题库）map映射表
            Map<Long, List<CourseBankType>> courseParentIdBankMap = courseBankTypeService.groupByCourseIdList(parentIdList);
            validateStrategyList.add(new DefaultBankTypeValidateStrategy(courseParentIdBankMap, courseIdParentIdMap));
        }

        //获取（身份证-已报名科目）map一映射表，校验学员是否已经报名
        List<String> statusList = Arrays.asList(StudentConst.AuditCode.STATUS_PASS.getCode(), StudentConst.AuditCode.STATUS_DISABLED.getCode());
        List<StudentCourse> studentCourse = studentCourseService.listByIdCardList(isCardList, statusList);
        Map<String, List<StudentCourse>> idCardStudentCourseMap = studentCourse.stream().collect(Collectors.groupingBy(StudentCourse::getIdCard));
        //获取 （身份证-名称）map映射表，校验学员是否同身份证不同名称
        Map<String, String> studentNameMap = studentCourse.stream().collect(Collectors
                .toMap(StudentCourse::getIdCard, StudentCourse::getStudentName, (oldValue, newValue) -> oldValue));
        validateStrategyList.add(new StudentValidateStrategy(idCardStudentCourseMap, studentNameMap));
        return validateStrategyList;
    }

    public String assembleMessage(List<ValidError<OrderItem>> list) {
        if (ObjectUtil.isEmpty(list)) {
            logger.info("错误列表为空，无法拼接报错信息");
            return "";
        }
        StringBuilder sb = new StringBuilder();
        int size = list.size();
        String code = CollectionUtil.getFirst(list).getCustomizeCode();
        if (ObjectUtil.equal(code, ExceptionCodeEnum.ENROLL.getCode())) {
            sb.append("以下学员已报名相同科目且在有效期内：\n");
            for (int i = 0; i < size; i++) {
                sb.append(list.get(i).getData().getName()).append("、");
            }
            sb.deleteCharAt(sb.length() - 1);
            sb.append("\n请核对后重新提交");
        } else {
            ValidError<OrderItem> validError = list.get(0);
            sb.append("第");
            sb.append(validError.getOrderNum());
            sb.append("条记录");
            validError.getErrorInfoList().forEach(errorInfo -> sb.append(errorInfo).append(";"));
            sb.append('\n');
        }
        return sb.toString();
    }
}
